/**
 * @file       forward_list_base.impl.hpp
 * @brief
 * @date       2021-01-25
 * @author     Peter
 * @copyright
 *      Peter of [ThinkSpirit Laboratory](http://thinkspirit.org/)
 *   of [Nanjing University of Information Science & Technology](http://www.nuist.edu.cn/)
 *   all rights reserved
 */

#ifndef KERBAL_CONTAINER_DETAIL_FORWARD_LIST_BASE_FORWARD_LIST_BASE_IMPL_HPP
#define KERBAL_CONTAINER_DETAIL_FORWARD_LIST_BASE_FORWARD_LIST_BASE_IMPL_HPP

#include <kerbal/algorithm/swap.hpp>
#include <kerbal/assign/generic_assign.hpp>
#include <kerbal/compare/basic_compare.hpp>
#include <kerbal/compatibility/constexpr.hpp>
#include <kerbal/compatibility/move.hpp>
#include <kerbal/compatibility/noexcept.hpp>
#include <kerbal/config/exceptions.hpp>
#include <kerbal/iterator/iterator.hpp>
#include <kerbal/type_traits/conditional.hpp>
#include <kerbal/type_traits/enable_if.hpp>
#include <kerbal/type_traits/integral_constant.hpp>
#include <kerbal/utility/declval.hpp>
#include <kerbal/utility/in_place.hpp>

#if __cplusplus < 201103L
#	include <kerbal/macro/macro_concat.hpp>
#	include <kerbal/macro/ppexpand.hpp>
#endif

#if __cplusplus >= 201103L
#	include <kerbal/compatibility/move.hpp>
#	include <kerbal/iterator/move_iterator.hpp>
#	include <kerbal/utility/forward.hpp>
#endif

#if !KERBAL_HAS_EXCEPTIONS_SUPPORT
#	include <kerbal/memory/bad_alloc.hpp>
#	include <kerbal/utility/throw_this_exception.hpp>
#endif

#include <climits> // CHAR_BIT
#include <cstddef> // std::size_t

#include <functional>
#include <typeinfo>

#if __cplusplus >= 201703L
#	if __has_include(<memory_resource>)
#		include <kerbal/type_traits/is_trivially_destructible.hpp>
#		include <memory_resource>
#	endif
#endif

#include <kerbal/container/detail/forward_list_base/forward_list_base.decl.hpp>


namespace kerbal
{

	namespace container
	{

		namespace detail
		{

		//===================
		//===================
		// fl_type_unrelated

		//===================
		// capacity

			KERBAL_CONSTEXPR14
			inline
			bool
			fl_type_unrelated::
			empty() const KERBAL_NOEXCEPT
			{
				return this->k_head.next == NULL;
			}

			KERBAL_CONSTEXPR14
			inline
			fl_type_unrelated::size_type
			fl_type_unrelated::
			size() const KERBAL_NOEXCEPT
			{
				basic_const_iterator first(this->basic_cbegin());
				basic_const_iterator const cend(this->basic_cend());
				basic_iterator::difference_type sz = 0;
				while (first != cend) {
					++first;
					++sz;
				}
				return sz;
			}


		//===================
		// operation

			KERBAL_CONSTEXPR14
			inline
			void
			fl_type_unrelated::
			k_iter_swap_after(basic_const_iterator before_a, basic_const_iterator before_b) KERBAL_NOEXCEPT
			{
				node_base * pba = before_a.cast_to_mutable().current;
				node_base * pbb = before_b.cast_to_mutable().current;
				kerbal::algorithm::swap(pba->next, pbb->next);
				node_base * pa = pba->next;
				node_base * pb = pbb->next;
				kerbal::algorithm::swap(pa->next, pb->next);
			}

			KERBAL_CONSTEXPR14
			inline
			void
			fl_type_unrelated::
			k_reverse_after(basic_const_iterator before_first, basic_const_iterator last) KERBAL_NOEXCEPT
			{
				basic_iterator it(before_first.cast_to_mutable()); ++it;
				basic_iterator next(it);
				basic_iterator end(last.cast_to_mutable());
				while (it != last) {
					++next;
					it.current->next = end.current;
					end = it;
					it = next;
				}
				before_first.cast_to_mutable().current->next = end.current;
			}

			KERBAL_CONSTEXPR14
			inline
			void
			fl_type_unrelated::
			reverse() KERBAL_NOEXCEPT
			{
				k_reverse_after(this->basic_cbefore_begin(), this->basic_cend());
			}

			KERBAL_CONSTEXPR14
			inline
			void
			fl_type_unrelated::
			k_splice_after(
				basic_const_iterator before_pos,
				fl_type_unrelated & other
			) KERBAL_NOEXCEPT
			{
				k_splice_after(before_pos, other.basic_cbefore_begin(), other.basic_cend());
			}

			KERBAL_CONSTEXPR14
			inline
			void
			fl_type_unrelated::
			k_splice_after(
				basic_const_iterator before_pos,
				basic_const_iterator before_opos
			) KERBAL_NOEXCEPT
			{
				node_base * p = k_unhook_node_after(before_opos);
				k_hook_node_after(before_pos, p);
			}

			KERBAL_CONSTEXPR14
			inline
			void
			fl_type_unrelated::
			k_splice_after(
				basic_const_iterator before_pos,
				basic_const_iterator before_first, basic_const_iterator last
			) KERBAL_NOEXCEPT
			{
				basic_const_iterator back(before_first);
				if (back.current->next != last.current) {
					++back;
					while (back.current->next != last.current) {
						++back;
					}
					node_base * start = k_unhook_node_after(before_first, last);
					k_hook_node_after(before_pos, start, back.cast_to_mutable().current);
				}
			}

#	if __cplusplus >= 201103L

			KERBAL_CONSTEXPR14
			inline
			void
			fl_type_unrelated::
			k_splice_after(
				basic_const_iterator before_pos,
				fl_type_unrelated && other
			) KERBAL_NOEXCEPT
			{
				k_splice_after(before_pos, other.basic_cbefore_begin(), other.basic_cend());
			}

#	endif

			KERBAL_CONSTEXPR14
			inline
			void
			fl_type_unrelated::
			k_radix_sort_back_fill_after(
				kerbal::type_traits::false_type /*asc*/,
				kerbal::type_traits::false_type /*unsigned*/,
				basic_iterator before_insert_pos,
				fl_type_unrelated buckets[], basic_iterator bucket_backs[], std::size_t BUCKETS_NUM
			) KERBAL_NOEXCEPT
			{
				node_base * last_bucket_front = before_insert_pos.current->next;
				std::size_t i = BUCKETS_NUM;
				while (i > 0) {
					--i;
					bucket_backs[i].current->next = last_bucket_front;
					last_bucket_front = buckets[i].basic_begin().current;
					// k_splice_after(before_insert_pos, buckets[i]); // O(n)
				}
				before_insert_pos.current->next = last_bucket_front;
			}

			KERBAL_CONSTEXPR14
			inline
			void
			fl_type_unrelated::
			k_radix_sort_back_fill_after(
				kerbal::type_traits::true_type /*desc*/,
				kerbal::type_traits::false_type /*unsigned*/,
				basic_iterator before_insert_pos,
				fl_type_unrelated buckets[], basic_iterator bucket_backs[], std::size_t BUCKETS_NUM
			) KERBAL_NOEXCEPT
			{
				node_base * last_bucket_front = before_insert_pos.current->next;
				for (std::size_t i = 0; i < BUCKETS_NUM; ++i) {
					bucket_backs[i].current->next = last_bucket_front;
					last_bucket_front = buckets[i].basic_begin().current;

					// k_splice_after(before_insert_pos, buckets[i]); // O(n)
				}
				before_insert_pos.current->next = last_bucket_front;
			}

			KERBAL_CONSTEXPR14
			inline
			void
			fl_type_unrelated::
			k_radix_sort_back_fill_after(
				kerbal::type_traits::false_type /*asc*/,
				kerbal::type_traits::true_type /*signed*/,
				basic_iterator before_insert_pos,
				fl_type_unrelated buckets[], basic_iterator bucket_backs[], std::size_t BUCKETS_NUM
			) KERBAL_NOEXCEPT
			{
				node_base * last_bucket_front = before_insert_pos.current->next;
				{
					std::size_t i = BUCKETS_NUM / 2;
					while (i > 0) {
						--i;

						bucket_backs[i].current->next = last_bucket_front;
						last_bucket_front = buckets[i].basic_begin().current;

						// k_splice_after(before_insert_pos, buckets[i]); // O(n)
					}
				}
				{
					std::size_t i = BUCKETS_NUM;
					while (i > BUCKETS_NUM / 2) {
						--i;

						bucket_backs[i].current->next = last_bucket_front;
						last_bucket_front = buckets[i].basic_begin().current;

						// k_splice_after(before_insert_pos, buckets[i]); // O(n)
					}
				}
				before_insert_pos.current->next = last_bucket_front;
			}

			KERBAL_CONSTEXPR14
			inline
			void
			fl_type_unrelated::
			k_radix_sort_back_fill_after(
				kerbal::type_traits::true_type /*desc*/,
				kerbal::type_traits::true_type /*signed*/,
				basic_iterator before_insert_pos,
				fl_type_unrelated buckets[], basic_iterator bucket_backs[], std::size_t BUCKETS_NUM
			) KERBAL_NOEXCEPT
			{
				node_base * last_bucket_front = before_insert_pos.current->next;
				for (std::size_t i = BUCKETS_NUM / 2; i < BUCKETS_NUM; ++i) {
					bucket_backs[i].current->next = last_bucket_front;
					last_bucket_front = buckets[i].basic_begin().current;

					// k_splice_after(before_insert_pos, buckets[i]); // O(n)
				}
				for (std::size_t i = 0; i < BUCKETS_NUM / 2; ++i) {
					bucket_backs[i].current->next = last_bucket_front;
					last_bucket_front = buckets[i].basic_begin().current;

					// k_splice_after(before_insert_pos, buckets[i]); // O(n)
				}
				before_insert_pos.current->next = last_bucket_front;
			}


		//===================
		// private

			KERBAL_CONSTEXPR14
			inline
			void
			fl_type_unrelated::
			k_hook_node_after(
				basic_const_iterator before_pos,
				node_base * p
			) KERBAL_NOEXCEPT
			{
				basic_iterator pos_mut(before_pos.cast_to_mutable());
				p->next = pos_mut.current->next;
				pos_mut.current->next = p;
			}

			KERBAL_CONSTEXPR14
			inline
			void
			fl_type_unrelated::
			k_hook_node_after(
				basic_const_iterator before_pos,
				node_base * start, node_base * back
			) KERBAL_NOEXCEPT
			{
				basic_iterator pos_mut(before_pos.cast_to_mutable());
				back->next = pos_mut.current->next;
				pos_mut.current->next = start;
			}

			KERBAL_CONSTEXPR14
			inline
			fl_type_unrelated::node_base *
			fl_type_unrelated::
			k_unhook_node_after(
				basic_const_iterator before_pos
			) KERBAL_NOEXCEPT
			{
				basic_iterator pos_mut(before_pos.cast_to_mutable());
				node_base * current = pos_mut.current;
				node_base * after = current->next;
				current->next = after->next;
				return after;
			}

			// pre-cond: first != last;
			KERBAL_CONSTEXPR14
			inline
			fl_type_unrelated::node_base *
			fl_type_unrelated::
			k_unhook_node_after(
				basic_const_iterator before_first, basic_const_iterator last
			) KERBAL_NOEXCEPT
			{
				basic_iterator first_mut(before_first.cast_to_mutable());
				basic_iterator last_mut(last.cast_to_mutable());
				node_base * ret = first_mut.current->next;
				first_mut.current->next = last_mut.current;
				return ret;
			}

			// pre-cond: lhs and rhs are lists of same type
			KERBAL_CONSTEXPR14
			inline
			void
			fl_type_unrelated::
			k_swap_type_unrelated(
				fl_type_unrelated & lhs,
				fl_type_unrelated & rhs
			) KERBAL_NOEXCEPT
			{
				kerbal::algorithm::swap(lhs.k_head.next, rhs.k_head.next);
			}


		//===================
		//===================
		// fl_type_only

		//===================
		// construct/copy/destroy

#	if __cplusplus >= 201103L

			// pre-cond: allocator allows
			template <typename T>
			KERBAL_CONSTEXPR14
			fl_type_only<T>::
			fl_type_only(fl_type_only && src) KERBAL_NOEXCEPT :
				fl_type_unrelated(static_cast<fl_type_unrelated &&>(src))
			{
			}

			// move construct using allocator, allocator is equal
			template <typename T>
			KERBAL_CONSTEXPR14
			void
			fl_type_only<T>::
			k_move_cnstrct_ua_ae(fl_type_only && src) KERBAL_NOEXCEPT
			{
				fl_type_unrelated::k_swap_type_unrelated(
					static_cast<fl_type_unrelated &>(src),
					static_cast<fl_type_unrelated &>(*this)
				);
			}

			// move construct using allocator, allocator is not equal
			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_move_cnstrct_ua_ane(
				NodeAllocator & this_alloc,
				fl_type_only && src
			)
			{
				if (src.empty()) {
					return;
				}
				sl_node_chain<T> chain(
					k_build_new_nodes_range_unguarded(
						this_alloc,
						kerbal::iterator::make_move_iterator(src.begin()),
						kerbal::iterator::make_move_iterator(src.end())
					)
				);
				fl_type_unrelated::k_hook_node_after(this->basic_before_begin(), chain.start, chain.back);
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_move_cnstrct_ua_helper(
				NodeAllocator & this_alloc,
				NodeAllocator && src_alloc, fl_type_only && src,
				kerbal::type_traits::false_type /*is_always_equal*/
			)
			{
				if (this_alloc != src_alloc) {
					this->k_move_cnstrct_ua_ane(this_alloc, kerbal::compatibility::move(src));
				} else {
					this->k_move_cnstrct_ua_ae(kerbal::compatibility::move(src));
				}
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR14
			void
			fl_type_only<T>::
			k_move_cnstrct_ua_helper(
				NodeAllocator & /*this_alloc*/,
				NodeAllocator && /*src_alloc*/, fl_type_only && src,
				kerbal::type_traits::true_type /*is_always_equal*/
			) KERBAL_NOEXCEPT
			{
				this->k_move_cnstrct_ua_ae(kerbal::compatibility::move(src));
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR14
			fl_type_only<T>::
			fl_type_only(
				NodeAllocator & this_alloc,
				NodeAllocator && src_alloc, fl_type_only && src
			)
				KERBAL_CONDITIONAL_NOEXCEPT(
					is_nothrow_move_constructible_using_allocator<NodeAllocator>::value
				) :
				fl_type_unrelated()
			{
				typedef kerbal::memory::allocator_traits<NodeAllocator> allocator_traits;
				typedef typename allocator_traits::is_always_equal is_always_equal;

				this->k_move_cnstrct_ua_helper(
					this_alloc,
					kerbal::compatibility::move(src_alloc), kerbal::compatibility::move(src),
					is_always_equal()
				);
			}

#	endif

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			fl_type_only<T>::
			fl_type_only(
				NodeAllocator & alloc,
				size_type n
			) :
				fl_type_unrelated()
			{
				if (n == 0) {
					return;
				}
				sl_node_chain<T> chain(k_build_n_new_nodes_unguarded(alloc, n));
				k_hook_node_after(this->basic_cbefore_begin(), chain.start, chain.back);
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			fl_type_only<T>::
			fl_type_only(
				NodeAllocator & alloc,
				size_type n, const_reference val
			) :
				fl_type_unrelated()
			{
				if (n == 0) {
					return;
				}
				sl_node_chain<T> chain(k_build_n_new_nodes_unguarded(alloc, n, val));
				k_hook_node_after(this->basic_cbefore_begin(), chain.start, chain.back);
			}

			template <typename T>
			template <typename NodeAllocator, typename InputIterator>
			KERBAL_CONSTEXPR20
			fl_type_only<T>::
			fl_type_only(
				NodeAllocator & alloc,
				InputIterator first, InputIterator last,
				typename kerbal::type_traits::enable_if<
					kerbal::iterator::is_input_compatible_iterator<InputIterator>::value, int
				>::type
			) :
				fl_type_unrelated()
			{
				k_insert_after_using_allocator(alloc, this->cbefore_begin(), first, last);
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_destroy_using_allocator(NodeAllocator & alloc) KERBAL_NOEXCEPT
			{
				this->k_consecutive_destroy_node(alloc, this->k_head.next, NULL);
			}


		//===================
		// assign

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_cpy_ass_ua_impl(
				NodeAllocator & alloc,
				const NodeAllocator & src_alloc, const fl_type_only & src,
				CPYASS_VER_NOT_PROPAGATE
			)
			{
				if (alloc != src_alloc) {
					this->k_destroy_using_allocator(alloc);
					this->k_head.next = NULL;
				}
				this->k_assign_using_allocator(alloc, src.cbegin(), src.cend());
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_cpy_ass_ua_impl(
				NodeAllocator & alloc,
				const NodeAllocator & src_alloc, const fl_type_only & src,
				CPYASS_VER_PROPAGATE
			)
			{
				if (alloc != src_alloc) {
					this->k_destroy_using_allocator(alloc);
					this->k_head.next = NULL;
				}
				alloc = src_alloc;
				this->k_assign_using_allocator(alloc, src.cbegin(), src.cend());
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_cpy_ass_ua_impl(
				NodeAllocator & alloc,
				const NodeAllocator & /*src_alloc*/, const fl_type_only & src,
				CPYASS_VER_ALWAYS_EQUAL
			)
			{
				this->k_assign_using_allocator(alloc, src.cbegin(), src.cend());
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_assign_using_allocator(
				NodeAllocator & alloc,
				const NodeAllocator & src_alloc, const fl_type_only & src
			)
			{
				typedef kerbal::memory::allocator_traits<NodeAllocator> allocator_traits;
				typedef typename allocator_traits::propagate_on_container_copy_assignment propagate;
				typedef typename allocator_traits::is_always_equal is_always_equal;

				typedef typename kerbal::type_traits::conditional<
					is_always_equal::value,
					CPYASS_VER_ALWAYS_EQUAL,
					typename kerbal::type_traits::conditional<
						propagate::value,
						CPYASS_VER_PROPAGATE,
						CPYASS_VER_NOT_PROPAGATE
					>::type
				>::type VER;

				this->k_cpy_ass_ua_impl(alloc, src_alloc, src, VER());
			}


#		if __cplusplus >= 201103L

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_move_assign(NodeAllocator & alloc, fl_type_only && src) KERBAL_NOEXCEPT
			{
				this->k_destroy_using_allocator(alloc);
				this->k_head.next = NULL;
				fl_type_unrelated::k_swap_type_unrelated(
					static_cast<fl_type_unrelated &>(src),
					static_cast<fl_type_unrelated &>(*this)
				);
			}

			// move assign using allocator, allocator is equal
			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_mov_ass_ua_ae(NodeAllocator & alloc, fl_type_only && src) KERBAL_NOEXCEPT
			{
				this->k_move_assign(alloc, kerbal::compatibility::move(src));
			}

			// move assign using allocator, allocator is not equal
			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_mov_ass_ua_ane(NodeAllocator & alloc, fl_type_only && src)
			{
				this->k_assign_using_allocator(
					alloc,
					kerbal::iterator::make_move_iterator(src.begin()),
					kerbal::iterator::make_move_iterator(src.end())
				);
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_mov_ass_ua_impl(
				NodeAllocator & alloc,
				NodeAllocator && src_alloc, fl_type_only && src,
				MOVASS_VER_NOT_PROPAGATE
			)
			{
				if (alloc != src_alloc) {
					this->k_mov_ass_ua_ane(alloc, kerbal::compatibility::move(src));
				} else {
					this->k_mov_ass_ua_ae(alloc, kerbal::compatibility::move(src));
				}
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_mov_ass_ua_impl(
				NodeAllocator & alloc,
				NodeAllocator && src_alloc, fl_type_only && src,
				MOVASS_VER_PROPAGATE
			)
			{
				this->k_destroy_using_allocator(alloc);
				this->k_head.next = NULL;
				alloc = kerbal::compatibility::move(src_alloc);
				fl_type_unrelated::k_swap_type_unrelated(
					static_cast<fl_type_unrelated &>(src),
					static_cast<fl_type_unrelated &>(*this)
				);
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_mov_ass_ua_impl(
				NodeAllocator & alloc,
				NodeAllocator && /*src_alloc*/, fl_type_only && src,
				MOVASS_VER_ALWAYS_EQUAL
			) KERBAL_NOEXCEPT
			{
				this->k_mov_ass_ua_ae(alloc, kerbal::compatibility::move(src));
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_assign_using_allocator(
				NodeAllocator & alloc,
				NodeAllocator && src_alloc, fl_type_only && src
			)
				KERBAL_CONDITIONAL_NOEXCEPT(is_nothrow_move_assign_using_allocator<NodeAllocator>::value)
			{
				typedef kerbal::memory::allocator_traits<NodeAllocator> allocator_traits;
				typedef typename allocator_traits::propagate_on_container_move_assignment propagate;
				typedef typename allocator_traits::is_always_equal is_always_equal;

				typedef typename kerbal::type_traits::conditional<
					is_always_equal::value,
					MOVASS_VER_ALWAYS_EQUAL,
					typename kerbal::type_traits::conditional<
						propagate::value,
						MOVASS_VER_PROPAGATE,
						MOVASS_VER_NOT_PROPAGATE
					>::type
				>::type VER;

				this->k_mov_ass_ua_impl(
					alloc,
					kerbal::compatibility::move(src_alloc),
					kerbal::compatibility::move(src),
					VER()
				);
			}

#		endif

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_assign_using_allocator(
				NodeAllocator & alloc,
				size_type count, const_reference val
			)
			{
				const_iterator before_it(this->before_begin());
				iterator it(this->begin());
				const_iterator const cend(this->cend());
				while (count != 0) {
					if (it != cend) {
						kerbal::assign::generic_assign(*it, val); // *it = val;
						--count;
						before_it = it;
						++it;
					} else {
						k_insert_after_using_allocator(alloc, before_it, count, val);
						return;
					}
				}
				k_erase_after_using_allocator(alloc, before_it, cend);
			}

			template <typename T>
			template <typename NodeAllocator, typename InputIterator>
			KERBAL_CONSTEXPR20
			typename kerbal::type_traits::enable_if<
				kerbal::iterator::is_input_compatible_iterator<InputIterator>::value
			>::type
			fl_type_only<T>::
			k_assign_using_allocator(
				NodeAllocator & alloc,
				InputIterator first, InputIterator last
			)
			{
				iterator before_it(this->before_begin());
				iterator it(this->begin());
				const_iterator const cend(this->cend());
				while (first != last) {
					if (it != cend) {
						kerbal::assign::generic_assign(*it, *first); // *it = *first;
						++first;
						before_it = it;
						++it;
					} else {
						k_insert_after_using_allocator(alloc, before_it, first, last);
						return;
					}
				}
				k_erase_after_using_allocator(alloc, before_it, cend);
			}


		//===================
		// element access

			template <typename T>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::reference
			fl_type_only<T>::
			front() KERBAL_NOEXCEPT
			{
				return node::reinterpret_as(this->k_head.next)->member();
			}

			template <typename T>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::const_reference
			fl_type_only<T>::
			front() const KERBAL_NOEXCEPT
			{
				return node::reinterpret_as(this->k_head.next)->member();
			}


		//===================
		// iterator

			template <typename T>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::iterator
			fl_type_only<T>::
			before_begin() KERBAL_NOEXCEPT
			{
				return iterator(&this->k_head);
			}

			template <typename T>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::const_iterator
			fl_type_only<T>::
			before_begin() const KERBAL_NOEXCEPT
			{
				return const_iterator(&this->k_head);
			}

			template <typename T>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::const_iterator
			fl_type_only<T>::
			cbefore_begin() const KERBAL_NOEXCEPT
			{
				return this->before_begin();
			}

			template <typename T>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::iterator
			fl_type_only<T>::
			begin() KERBAL_NOEXCEPT
			{
				return iterator(this->k_head.next);
			}

			template <typename T>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::const_iterator
			fl_type_only<T>::
			begin() const KERBAL_NOEXCEPT
			{
				return const_iterator(this->k_head.next);
			}

			template <typename T>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::const_iterator
			fl_type_only<T>::
			cbegin() const KERBAL_NOEXCEPT
			{
				return this->begin();
			}

			template <typename T>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::iterator
			fl_type_only<T>::
			end() KERBAL_NOEXCEPT
			{
				return iterator(NULL);
			}

			template <typename T>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::const_iterator
			fl_type_only<T>::
			end() const KERBAL_NOEXCEPT
			{
				return const_iterator(NULL);
			}

			template <typename T>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::const_iterator
			fl_type_only<T>::
			cend() const KERBAL_NOEXCEPT
			{
				return this->end();
			}

			template <typename T>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::iterator
			fl_type_only<T>::
			nth(size_type index) KERBAL_NOEXCEPT
			{
				return kerbal::iterator::next(this->begin(), index);
			}

			template <typename T>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::const_iterator
			fl_type_only<T>::
			nth(size_type index) const KERBAL_NOEXCEPT
			{
				return kerbal::iterator::next(this->cbegin(), index);
			}

			template <typename T>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::size_type
			fl_type_only<T>::
			index_of(iterator it) KERBAL_NOEXCEPT
			{
				return kerbal::iterator::distance(this->begin(), it);
			}

			template <typename T>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::size_type
			fl_type_only<T>::
			index_of(const_iterator it) const KERBAL_NOEXCEPT
			{
				return kerbal::iterator::distance(this->cbegin(), it);
			}


		//===================
		// lookup

			template <typename T>
			template <typename UnaryPredict>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::const_iterator
			fl_type_only<T>::
			k_find_before_if_impl(
				const_iterator before_since, const_iterator end,
				UnaryPredict predict
			)
			{
				const_iterator it = kerbal::iterator::next(before_since);
				while (it != end) {
					if (predict(*it)) {
						break;
					}
					before_since = it;
					++it;
				}
				return before_since;
			}

			template <typename T>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::const_iterator
			fl_type_only<T>::
			k_find_before_impl(
				const_iterator before_since, const_iterator end,
				const_reference target
			)
			{
				const_iterator it = kerbal::iterator::next(before_since);
				while (it != end) {
					if (*it == target) {
						break;
					}
					before_since = it;
					++it;
				}
				return before_since;
			}

			template <typename T>
			template <typename UnaryPredict>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::iterator
			fl_type_only<T>::
			find_before_if(
				UnaryPredict predict,
				const_iterator before_since
			)
			{
				return k_find_before_if_impl(before_since, this->cend(), predict).cast_to_mutable();
			}

			template <typename T>
			template <typename UnaryPredict>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::const_iterator
			fl_type_only<T>::
			find_before_if(
				UnaryPredict predict,
				const_iterator before_since
			) const
			{
				return k_find_before_if_impl(before_since, this->cend(), predict);
			}

			template <typename T>
			template <typename UnaryPredict>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::iterator
			fl_type_only<T>::
			find_before_if(UnaryPredict predict)
			{
				return this->find_before_if(predict, this->cbefore_begin());
			}

			template <typename T>
			template <typename UnaryPredict>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::const_iterator
			fl_type_only<T>::
			find_before_if(UnaryPredict predict) const
			{
				return this->find_before_if(predict, this->cbefore_begin());
			}

			template <typename T>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::iterator
			fl_type_only<T>::
			find_before(
				const_reference target,
				const_iterator before_since
			)
			{
				return k_find_before_impl(before_since, this->cend(), target).cast_to_mutable();
			}

			template <typename T>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::const_iterator
			fl_type_only<T>::
			find_before(
				const_reference target,
				const_iterator before_since
			) const
			{
				return k_find_before_impl(before_since, this->cend(), target);
			}

			template <typename T>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::iterator
			fl_type_only<T>::
			find_before(const_reference target)
			{
				return this->find_before(target, this->cbefore_begin());
			}

			template <typename T>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::const_iterator
			fl_type_only<T>::
			find_before(const_reference target) const
			{
				return this->find_before(target, this->cbefore_begin());
			}


		//===================
		// insert

#		if __cplusplus >= 201103L

			template <typename T>
			template <typename NodeAllocator, typename ... Args>
			KERBAL_CONSTEXPR20
			typename
			fl_type_only<T>::iterator
			fl_type_only<T>::
			k_emplace_after_using_allocator(
				NodeAllocator & alloc,
				const_iterator before_pos,
				Args && ... args
			)
			{
				node * p = k_build_new_node(alloc, kerbal::utility::forward<Args>(args)...);
				fl_type_unrelated::k_hook_node_after(before_pos, p);
				return iterator(p);
			}

#		else

#		define EMPTY
#		define LEFT_JOIN_COMMA(exp) , exp
#		define TARGS_DECL(i) typename KERBAL_MACRO_CONCAT(Arg, i)
#		define ARGS_DECL(i) const KERBAL_MACRO_CONCAT(Arg, i) & KERBAL_MACRO_CONCAT(arg, i)
#		define ARGS_USE(i) KERBAL_MACRO_CONCAT(arg, i)
#		define FBODY(i) \
			template <typename T> \
			template < \
				typename NodeAllocator \
				KERBAL_OPT_PPEXPAND_WITH_COMMA_N(LEFT_JOIN_COMMA, EMPTY, TARGS_DECL, i) \
			> \
			typename \
			fl_type_only<T>::iterator \
			fl_type_only<T>:: \
			k_emplace_after_using_allocator( \
				NodeAllocator & alloc, \
				const_iterator before_pos \
				KERBAL_OPT_PPEXPAND_WITH_COMMA_N(LEFT_JOIN_COMMA, EMPTY, ARGS_DECL, i) \
			) \
			{ \
				node * p = k_build_new_node( \
					alloc \
					KERBAL_OPT_PPEXPAND_WITH_COMMA_N(LEFT_JOIN_COMMA, EMPTY, ARGS_USE, i) \
				); \
				fl_type_unrelated::k_hook_node_after(before_pos, p); \
				return iterator(p); \
			} \

			KERBAL_PPEXPAND_N(FBODY, KERBAL_PPEXPAND_EMPTY_SEPARATOR, 0)
			KERBAL_PPEXPAND_N(FBODY, KERBAL_PPEXPAND_EMPTY_SEPARATOR, 20)

#		undef EMPTY
#		undef LEFT_JOIN_COMMA
#		undef TARGS_DECL
#		undef ARGS_DECL
#		undef ARGS_USE
#		undef FBODY

#		endif

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			typename
			fl_type_only<T>::iterator
			fl_type_only<T>::
			k_insert_after_using_allocator(
				NodeAllocator & alloc,
				const_iterator before_pos,
				const_reference val
			)
			{
				return k_emplace_after_using_allocator(alloc, before_pos, val);
			}

#		if __cplusplus >= 201103L

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			typename
			fl_type_only<T>::iterator
			fl_type_only<T>::
			k_insert_after_using_allocator(
				NodeAllocator & alloc,
				const_iterator before_pos,
				rvalue_reference val
			)
			{
				return k_emplace_after_using_allocator(alloc, before_pos, kerbal::compatibility::move(val));
			}

#		endif

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			typename
			fl_type_only<T>::iterator
			fl_type_only<T>::
			k_insert_after_using_allocator(
				NodeAllocator & alloc,
				const_iterator before_pos,
				size_type n, const_reference val
			)
			{
				if (n == 0) {
					return before_pos.cast_to_mutable();
				}
				sl_node_chain<T> chain(k_build_n_new_nodes_unguarded(alloc, n, val));
				fl_type_unrelated::k_hook_node_after(before_pos, chain.start, chain.back);
				return iterator(chain.back);
			}

			template <typename T>
			template <typename NodeAllocator, typename InputIterator>
			KERBAL_CONSTEXPR20
			typename kerbal::type_traits::enable_if<
				kerbal::iterator::is_input_compatible_iterator<InputIterator>::value,
				typename fl_type_only<T>::iterator
			>::type
			fl_type_only<T>::
			k_insert_after_using_allocator(
				NodeAllocator & alloc,
				const_iterator before_pos,
				InputIterator first, InputIterator last
			)
			{
				if (first == last) {
					return before_pos.cast_to_mutable();
				}
				sl_node_chain<T> chain(k_build_new_nodes_range_unguarded(alloc, first, last));
				fl_type_unrelated::k_hook_node_after(before_pos, chain.start, chain.back);
				return iterator(chain.back);
			}

#		if __cplusplus >= 201103L

			template <typename T>
			template <typename NodeAllocator, typename ... Args>
			KERBAL_CONSTEXPR20
			typename
			fl_type_only<T>::reference
			fl_type_only<T>::
			k_emplace_front_using_allocator(NodeAllocator & alloc, Args && ... args)
			{
				node * p = k_build_new_node(alloc, kerbal::utility::forward<Args>(args)...);
				fl_type_unrelated::k_hook_node_after(this->basic_cbefore_begin(), p);
				return p->member();
			}

#		else

#		define EMPTY
#		define LEFT_JOIN_COMMA(exp) , exp
#		define TARGS_DECL(i) typename KERBAL_MACRO_CONCAT(Arg, i)
#		define ARGS_DECL(i) const KERBAL_MACRO_CONCAT(Arg, i) & KERBAL_MACRO_CONCAT(arg, i)
#		define ARGS_USE(i) KERBAL_MACRO_CONCAT(arg, i)
#		define FBODY(i) \
			template <typename T> \
			template < \
				typename NodeAllocator \
				KERBAL_OPT_PPEXPAND_WITH_COMMA_N(LEFT_JOIN_COMMA, EMPTY, TARGS_DECL, i) \
			> \
			typename \
			fl_type_only<T>::reference \
			fl_type_only<T>:: \
			k_emplace_front_using_allocator( \
				NodeAllocator & alloc \
				KERBAL_OPT_PPEXPAND_WITH_COMMA_N(LEFT_JOIN_COMMA, EMPTY, ARGS_DECL, i) \
			) \
			{ \
				node * p = k_build_new_node(alloc KERBAL_OPT_PPEXPAND_WITH_COMMA_N(LEFT_JOIN_COMMA, EMPTY, ARGS_USE, i)); \
				fl_type_unrelated::k_hook_node_after(this->basic_cbefore_begin(), p); \
				return p->member(); \
			} \

			KERBAL_PPEXPAND_N(FBODY, KERBAL_PPEXPAND_EMPTY_SEPARATOR, 0)
			KERBAL_PPEXPAND_N(FBODY, KERBAL_PPEXPAND_EMPTY_SEPARATOR, 20)

#		undef EMPTY
#		undef LEFT_JOIN_COMMA
#		undef TARGS_DECL
#		undef ARGS_DECL
#		undef ARGS_USE
#		undef FBODY

#		endif

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_push_front_using_allocator(NodeAllocator & alloc, const_reference val)
			{
				this->k_emplace_front_using_allocator(alloc, val);
			}

#		if __cplusplus >= 201103L

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_push_front_using_allocator(NodeAllocator & alloc, rvalue_reference val)
			{
				this->k_emplace_front_using_allocator(alloc, kerbal::compatibility::move(val));
			}

#		endif


		//===================
		// erase

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			typename
			fl_type_only<T>::iterator
			fl_type_only<T>::
			k_erase_after_using_allocator(
				NodeAllocator & alloc,
				const_iterator before_pos
			)
			{
				iterator pos_mut(before_pos.cast_to_mutable());
				node_base * p = fl_type_unrelated::k_unhook_node_after(pos_mut);
				k_destroy_node(alloc, p);
				return ++pos_mut;
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			typename
			fl_type_only<T>::iterator
			fl_type_only<T>::
			k_erase_after_using_allocator(
				NodeAllocator & alloc,
				const_iterator before_first, const_iterator last
			)
			{
				iterator first_mut(before_first.cast_to_mutable());
				iterator last_mut(last.cast_to_mutable());
				if (before_first != last) {
					node_base * first = fl_type_unrelated::k_unhook_node_after(first_mut, last_mut);
					node_base * last = last_mut.current;
					k_consecutive_destroy_node(alloc, first, last);
				}
				return ++first_mut;
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_pop_front_using_allocator(NodeAllocator & alloc)
			{
				k_erase_after_using_allocator(alloc, this->cbefore_begin());
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_clear_using_allocator(NodeAllocator & alloc)
				KERBAL_CONDITIONAL_NOEXCEPT(
					noexcept(
						kerbal::utility::declthis<fl_type_only>()->k_consecutive_destroy_node(
							alloc,
							kerbal::utility::declthis<fl_type_only>()->k_head.next,
							NULL
						)
					)
				)
			{
				k_consecutive_destroy_node(alloc, this->k_head.next, NULL);
				this->k_head.next = NULL;
			}


		//===================
		// operation

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_resize_using_allocator(NodeAllocator & alloc, size_type count)
			{
				const_iterator before_it(this->before_begin());
				iterator it(this->begin());
				const_iterator const cend(this->cend());
				while (count != 0) {
					if (it != cend) {
						--count;
						before_it = it;
						++it;
					} else {
						// pre-condition: count != 0
						sl_node_chain<T> chain(k_build_n_new_nodes_unguarded(alloc, count));
						fl_type_unrelated::k_hook_node_after(before_it, chain.start, chain.back);
						return;
					}
				}
				k_erase_after_using_allocator(alloc, before_it, cend);
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_resize_using_allocator(NodeAllocator & alloc, size_type count, const_reference value)
			{
				const_iterator before_it(this->before_begin());
				iterator it(this->begin());
				const_iterator const cend(this->cend());
				while (count != 0) {
					if (it != cend) {
						--count;
						before_it = it;
						++it;
					} else {
						// pre-condition: count != 0
						sl_node_chain<T> chain(k_build_n_new_nodes_unguarded(alloc, count, value));
						fl_type_unrelated::k_hook_node_after(before_it, chain.start, chain.back);
						return;
					}
				}
				k_erase_after_using_allocator(alloc, before_it, cend);
			}

			template <typename T>
			KERBAL_CONSTEXPR14
			void
			fl_type_only<T>::
			k_iter_swap_after(const_iterator before_a, const_iterator before_b) KERBAL_NOEXCEPT
			{
				fl_type_unrelated::k_iter_swap_after(before_a, before_b);
			}

			template <typename T>
			KERBAL_CONSTEXPR14
			void
			fl_type_only<T>::
			k_reverse_after(const_iterator before_first, const_iterator last) KERBAL_NOEXCEPT
			{
				fl_type_unrelated::k_reverse_after(before_first, last);
			}

			template <typename T>
			template <typename BinaryPredict>
			KERBAL_CONSTEXPR14
			void
			fl_type_only<T>::
			k_merge_impl(
				fl_type_only & other,
				BinaryPredict cmp, MERGE_VER_NOTHROW
			) KERBAL_NOEXCEPT
			{
				const_iterator it_other(other.cbegin());
				const_iterator it_this_before(this->cbefore_begin());
				const_iterator it_this(this->cbegin());
				const_iterator const cend(NULL);

				while (it_other != cend) {
					if (it_this != cend) {
						if (cmp(*it_other, *it_this)) {
							fl_type_unrelated::k_hook_node_after(it_this_before, it_other++.cast_to_mutable().current);
							++it_this_before;
						} else {
							it_this_before = it_this;
							++it_this;
						}
					} else {
						it_this_before.cast_to_mutable().current->next = it_other.cast_to_mutable().current;
						break;
					}
				}
				other.k_head.next = NULL;
			}

#		if KERBAL_HAS_EXCEPTIONS_SUPPORT

			template <typename T>
			template <typename BinaryPredict>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_merge_impl(
				fl_type_only & other, BinaryPredict cmp,
				MERGE_VER_MAY_THROW
			)
			{
				const_iterator it_other(other.cbegin());
				const_iterator it_this_before(this->cbefore_begin());
				const_iterator it_this(this->cbegin());
				const_iterator const cend(NULL);

				try {
					while (it_other != cend) {
						if (it_this != cend) {
							if (cmp(*it_other, *it_this)) {
								fl_type_unrelated::k_hook_node_after(it_this_before, it_other++.cast_to_mutable().current);
								++it_this_before;
							} else {
								it_this_before = it_this;
								++it_this;
							}
						} else {
							it_this_before.cast_to_mutable().current->next = it_other.cast_to_mutable().current;
							break;
						}
					}
				} catch (...) {
					other.k_head.next = it_other.cast_to_mutable().current;
					throw;
				}
				other.k_head.next = NULL;
			}

#		endif

			template <typename T>
			template <typename BinaryPredict>
			KERBAL_CONSTEXPR14
			void
			fl_type_only<T>::
			k_merge(fl_type_only & other, BinaryPredict cmp)
			{

#		if KERBAL_HAS_EXCEPTIONS_SUPPORT

#			if __cplusplus >= 201103L

				typedef typename kerbal::type_traits::conditional<
					noexcept(
						cmp(
							kerbal::utility::declval<const_reference>(),
							kerbal::utility::declval<const_reference>()
						)
					),
					MERGE_VER_NOTHROW,
					MERGE_VER_MAY_THROW
				>::type MERGE_VERSION;

#			else
				typedef MERGE_VER_MAY_THROW MERGE_VERSION;
#			endif
#		else
				typedef MERGE_VER_NOTHROW MERGE_VERSION;
#		endif

				this->k_merge_impl(other, cmp, MERGE_VERSION());

			}

			template <typename T>
			KERBAL_CONSTEXPR14
			void
			fl_type_only<T>::
			k_merge(fl_type_only & other)
			{
				this->k_merge(other, kerbal::compare::less<value_type>());
			}

#		if __cplusplus >= 201103L

			template <typename T>
			template <typename BinaryPredict>
			KERBAL_CONSTEXPR14
			void
			fl_type_only<T>::
			k_merge(fl_type_only && other, BinaryPredict cmp)
			{
				this->k_merge(other, cmp);
			}

			template <typename T>
			KERBAL_CONSTEXPR14
			void
			fl_type_only<T>::
			k_merge(fl_type_only && other)
			{
				this->k_merge(
					kerbal::compatibility::move(other),
					kerbal::compare::less<value_type>()
				);
			}

#		endif

			template <typename T>
			template <typename BinaryPredict>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::const_iterator
			fl_type_only<T>::
			k_merge_sort_merge_after_impl(
				const_iterator before_first, const_iterator before_mid, const_iterator before_last,
				BinaryPredict cmp,
				MSM_VER_NOTHROW
			)
			{
				const_iterator mid(before_mid); ++mid;
				const_iterator last(before_last); ++last;
				const_iterator before_i(before_first);
				const_iterator i(before_i); ++i;
				const_iterator j(mid);

				while (i != mid) {
					if (j != last) {
						if (cmp(*j, *i)) {
							fl_type_unrelated::k_hook_node_after(before_i, j++.cast_to_mutable().current);
							++before_i;
						} else {
							before_i = i;
							++i;
						}
					} else {
						before_mid.cast_to_mutable().current->next = last.cast_to_mutable().current;
						return before_mid;
					}
				}
				before_mid.cast_to_mutable().current->next = j.cast_to_mutable().current;
				return before_last;
			}

#		if KERBAL_HAS_EXCEPTIONS_SUPPORT

			template <typename T>
			template <typename BinaryPredict>
			KERBAL_CONSTEXPR20
			typename
			fl_type_only<T>::const_iterator
			fl_type_only<T>::
			k_merge_sort_merge_after_impl(
				const_iterator before_first, const_iterator before_mid, const_iterator before_last,
				BinaryPredict cmp,
				MSM_VER_MAY_THROW
			)
			{
				const_iterator mid(before_mid); ++mid;
				const_iterator last(before_last); ++last;
				const_iterator before_i(before_first);
				const_iterator i(before_i); ++i;
				const_iterator j(mid);

				try {
					while (i != mid) {
						if (j != last) {
							if (cmp(*j, *i)) {
								fl_type_unrelated::k_hook_node_after(before_i, j++.cast_to_mutable().current);
								++before_i;
							} else {
								before_i = i;
								++i;
							}
						} else {
							before_mid.cast_to_mutable().current->next = last.cast_to_mutable().current;
							return before_mid;
						}
					}
				} catch (...) {
					before_mid.cast_to_mutable().current->next = j.cast_to_mutable().current;
					throw;
				}
				before_mid.cast_to_mutable().current->next = j.cast_to_mutable().current;
				return before_last;
			}

#		endif

			template <typename T>
			template <typename BinaryPredict>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::const_iterator
			fl_type_only<T>::
			k_merge_sort_merge_after(
				const_iterator before_first, const_iterator before_mid, const_iterator before_last,
				BinaryPredict cmp
			)
			{

#		if KERBAL_HAS_EXCEPTIONS_SUPPORT

#			if __cplusplus >= 201103L

				typedef typename kerbal::type_traits::conditional<
					noexcept(
						cmp(
							kerbal::utility::declval<const_reference>(),
							kerbal::utility::declval<const_reference>()
						)
					),
					MSM_VER_NOTHROW,
					MSM_VER_MAY_THROW
				>::type MSM_VERSION;

#			else
				typedef MSM_VER_MAY_THROW MSM_VERSION;
#			endif
#		else
				typedef MSM_VER_NOTHROW MSM_VERSION;
#		endif

				return k_merge_sort_merge_after_impl(before_first, before_mid, before_last, cmp, MSM_VERSION());

			}

			template <typename T>
			template <typename BinaryPredict>
			KERBAL_CONSTEXPR14
			typename
			fl_type_only<T>::const_iterator
			fl_type_only<T>::
			k_merge_sort_n_after(const_iterator before_first, size_type n, BinaryPredict cmp)
			{
				if (n == 0) {
					return before_first;
				}
				if (n == 1) {
					++before_first;
					return before_first;
				}
				if (n == 2) {
					const_iterator a(before_first); ++a;
					const_iterator b(a); ++b;
					if (cmp(*b, *a)) {
						iterator first_mut(before_first.cast_to_mutable());
						iterator a_mut(a.cast_to_mutable());
						iterator b_mut(b.cast_to_mutable());
						a_mut.current->next = b_mut.current->next;
						b_mut.current->next = a_mut.current;
						first_mut.current->next = b_mut.current;
						return a;
					} else {
						return b;
					}
				}

				size_type first_len(n / 2);
				const_iterator before_mid(k_merge_sort_n_after(before_first, first_len, cmp));
				const_iterator before_last(k_merge_sort_n_after(before_mid, n - first_len, cmp));
				return k_merge_sort_merge_after(before_first, before_mid, before_last, cmp);
			}

			template <typename T>
			template <typename BinaryPredict>
			KERBAL_CONSTEXPR14
			void
			fl_type_only<T>::
			k_merge_sort_after(const_iterator before_first, const_iterator last, BinaryPredict cmp)
			{
				k_merge_sort_n_after(before_first, kerbal::iterator::distance(before_first, last) - 1, cmp);
			}

			template <typename T>
			template <std::size_t RADIX_BIT_WIDTH>
			KERBAL_CONSTEXPR14
			void
			fl_type_only<T>::
			radix_sort_after(
				const_iterator before_first, const_iterator last, kerbal::type_traits::false_type asc,
				kerbal::type_traits::integral_constant<std::size_t, RADIX_BIT_WIDTH>
			) KERBAL_NOEXCEPT
			{
				typedef kerbal::type_traits::integral_constant<std::size_t, 1 << RADIX_BIT_WIDTH> BUCKETS_NUM;
				fl_type_unrelated buckets[2][BUCKETS_NUM::value];

				for (int i = 0; i < 2; ++i) {
					for (std::size_t j = 0; j < BUCKETS_NUM::value; ++j) {
						buckets[i][j].k_head.next = NULL;
					}
				}

				typedef kerbal::type_traits::integral_constant<std::size_t, sizeof(value_type) * CHAR_BIT> VALUE_TYPE_BIT_WIDTH;
				typedef kerbal::type_traits::integral_constant<std::size_t, VALUE_TYPE_BIT_WIDTH::value / RADIX_BIT_WIDTH + (VALUE_TYPE_BIT_WIDTH::value % RADIX_BIT_WIDTH != 0)> ROUNDS;

				basic_iterator bucket_backs[BUCKETS_NUM::value];

				// first round
				for (std::size_t i = 0; i < BUCKETS_NUM::value; ++i) {
					bucket_backs[i] = buckets[0][i].basic_before_begin();
				}
				for (const_iterator it(kerbal::iterator::next(before_first)); it != last; ) {
					int bucket_id = *it % BUCKETS_NUM::value;
					fl_type_unrelated & bucket_in = buckets[0][bucket_id];
					++it;
					bucket_in.k_splice_after(bucket_backs[bucket_id], before_first);
					++bucket_backs[bucket_id];
				}

				for (std::size_t round = 1; round < ROUNDS::value; ++round) {
					fl_type_unrelated (& buckets_from)[BUCKETS_NUM::value] = buckets[(round + 1) % 2];
					fl_type_unrelated (& buckets_to)[BUCKETS_NUM::value] = buckets[round % 2];

					for (std::size_t i = 0; i < BUCKETS_NUM::value; ++i) {
						buckets_to[i].k_head.next = NULL;
						bucket_backs[i] = buckets_to[i].basic_before_begin();
					}

					for (std::size_t i = 0; i < BUCKETS_NUM::value; ++i) {
						fl_type_unrelated & bucket_out = buckets_from[i];
						const_iterator it(bucket_out.basic_begin());
						const_iterator const cend(bucket_out.basic_end());
						while (it != cend) {
							int bucket_id = (*it >> (RADIX_BIT_WIDTH * round)) % BUCKETS_NUM::value;
							fl_type_unrelated & bucket_in = buckets_to[bucket_id];
							node_base * splice_node = (it++).cast_to_mutable().current;
							bucket_in.k_hook_node_after(bucket_backs[bucket_id], splice_node);
							bucket_backs[bucket_id].current = splice_node;
						}
					}
				}

				fl_type_unrelated::k_radix_sort_back_fill_after(
					asc,
					kerbal::type_traits::is_signed<value_type>(),
					before_first.cast_to_mutable(),
					buckets[(ROUNDS::value + 1) % 2], bucket_backs, BUCKETS_NUM::value
				);
			}

			template <typename T>
			template <std::size_t RADIX_BIT_WIDTH>
			KERBAL_CONSTEXPR14
			void
			fl_type_only<T>::
			radix_sort_after(
				const_iterator before_first, const_iterator last, kerbal::type_traits::true_type desc,
				kerbal::type_traits::integral_constant<std::size_t, RADIX_BIT_WIDTH>
			) KERBAL_NOEXCEPT
			{
				typedef kerbal::type_traits::integral_constant<std::size_t, 1 << RADIX_BIT_WIDTH> BUCKETS_NUM;
				fl_type_unrelated buckets[2][BUCKETS_NUM::value];

				for (int i = 0; i < 2; ++i) {
					for (std::size_t j = 0; j < BUCKETS_NUM::value; ++j) {
						buckets[i][j].k_head.next = NULL;
					}
				}

				typedef kerbal::type_traits::integral_constant<std::size_t, sizeof(value_type) * CHAR_BIT> VALUE_TYPE_BIT_WIDTH;
				typedef kerbal::type_traits::integral_constant<std::size_t, VALUE_TYPE_BIT_WIDTH::value / RADIX_BIT_WIDTH + (VALUE_TYPE_BIT_WIDTH::value % RADIX_BIT_WIDTH != 0)> ROUNDS;

				basic_iterator bucket_backs[BUCKETS_NUM::value];

				// first round
				for (std::size_t i = 0; i < BUCKETS_NUM::value; ++i) {
					bucket_backs[i] = buckets[0][i].basic_before_begin();
				}
				for (const_iterator it(kerbal::iterator::next(before_first)); it != last; ) {
					int bucket_id = *it % BUCKETS_NUM::value;
					fl_type_unrelated & bucket_in = buckets[0][bucket_id];
					++it;
					bucket_in.k_splice_after(bucket_backs[bucket_id], before_first);
					++bucket_backs[bucket_id];
				}

				for (std::size_t round = 1; round < ROUNDS::value; ++round) {
					fl_type_unrelated (& buckets_from)[BUCKETS_NUM::value] = buckets[(round + 1) % 2];
					fl_type_unrelated (& buckets_to)[BUCKETS_NUM::value] = buckets[round % 2];

					for (std::size_t i = 0; i < BUCKETS_NUM::value; ++i) {
						buckets_to[i].k_head.next = NULL;
						bucket_backs[i] = buckets_to[i].basic_before_begin();
					}

					std::size_t i = BUCKETS_NUM::value;
					while (i != 0) {
						--i;
						fl_type_unrelated & bucket_out = buckets_from[i];
						const_iterator it(bucket_out.basic_begin());
						const_iterator const cend(bucket_out.basic_end());
						while (it != cend) {
							int bucket_id = (*it >> (RADIX_BIT_WIDTH * round)) % BUCKETS_NUM::value;
							fl_type_unrelated & bucket_in = buckets_to[bucket_id];
							node_base * splice_node = (it++).cast_to_mutable().current;
							bucket_in.k_hook_node_after(bucket_backs[bucket_id], splice_node);
							bucket_backs[bucket_id].current = splice_node;
						}
					}
				}

				fl_type_unrelated::k_radix_sort_back_fill_after(
					desc,
					kerbal::type_traits::is_signed<value_type>(),
					before_first.cast_to_mutable(),
					buckets[(ROUNDS::value + 1) % 2], bucket_backs, BUCKETS_NUM::value
				);
			}

			template <typename T>
			template <typename Order>
			KERBAL_CONSTEXPR14
			void
			fl_type_only<T>::
			radix_sort_after(const_iterator before_first, const_iterator last, Order /*order*/) KERBAL_NOEXCEPT
			{
				radix_sort_after(
					before_first, last, kerbal::type_traits::bool_constant<Order::value>(),
					kerbal::type_traits::integral_constant<std::size_t, CHAR_BIT>()
				);
			}

			template <typename T>
			template <bool is_radix_sort_acceptable_type>
			KERBAL_CONSTEXPR14
			typename kerbal::type_traits::enable_if<is_radix_sort_acceptable_type>::type
			fl_type_only<T>::
			radix_sort_after(const_iterator before_first, const_iterator last) KERBAL_NOEXCEPT
			{
				radix_sort_after(before_first, last, kerbal::type_traits::false_type());
			}

			template <typename T>
			template <bool is_radix_sort_acceptable_type, typename BinaryPredict>
			KERBAL_CONSTEXPR14
			typename kerbal::type_traits::enable_if<is_radix_sort_acceptable_type>::type
			fl_type_only<T>::
			sort_after_method_overload(
				const_iterator before_first, const_iterator last,
				BinaryPredict cmp
			)
			{
				k_merge_sort_after(before_first, last, cmp);
			}

			template <typename T>
			template <bool is_radix_sort_acceptable_type>
			KERBAL_CONSTEXPR14
			typename kerbal::type_traits::enable_if<is_radix_sort_acceptable_type>::type
			fl_type_only<T>::
			sort_after_method_overload(
				const_iterator before_first, const_iterator last,
				kerbal::compare::less<value_type> /*cmp*/
			)
			{
				radix_sort_after(before_first, last, kerbal::type_traits::false_type());
			}

			template <typename T>
			template <bool is_radix_sort_acceptable_type>
			KERBAL_CONSTEXPR14
			typename kerbal::type_traits::enable_if<is_radix_sort_acceptable_type>::type
			fl_type_only<T>::
			sort_after_method_overload(
				const_iterator before_first, const_iterator last,
				kerbal::compare::greater<value_type> /*cmp*/
			)
			{
				radix_sort_after(before_first, last, kerbal::type_traits::true_type());
			}

			template <typename T>
			template <bool is_radix_sort_acceptable_type>
			KERBAL_CONSTEXPR14
			typename kerbal::type_traits::enable_if<is_radix_sort_acceptable_type>::type
			fl_type_only<T>::
			sort_after_method_overload(
				const_iterator before_first, const_iterator last,
				kerbal::compare::less<void> /*cmp*/
			)
			{
				radix_sort_after(before_first, last, kerbal::type_traits::false_type());
			}

			template <typename T>
			template <bool is_radix_sort_acceptable_type>
			KERBAL_CONSTEXPR14
			typename kerbal::type_traits::enable_if<is_radix_sort_acceptable_type>::type
			fl_type_only<T>::
			sort_after_method_overload(
				const_iterator before_first, const_iterator last,
				kerbal::compare::greater<void> /*cmp*/
			)
			{
				radix_sort_after(before_first, last, kerbal::type_traits::true_type());
			}

			template <typename T>
			template <bool is_radix_sort_acceptable_type>
			KERBAL_CONSTEXPR14
			typename kerbal::type_traits::enable_if<is_radix_sort_acceptable_type>::type
			fl_type_only<T>::
			sort_after_method_overload(
				const_iterator before_first, const_iterator last,
				std::less<value_type> /*cmp*/
			)
			{
				radix_sort_after(before_first, last, kerbal::type_traits::false_type());
			}

			template <typename T>
			template <bool is_radix_sort_acceptable_type>
			KERBAL_CONSTEXPR14
			typename kerbal::type_traits::enable_if<is_radix_sort_acceptable_type>::type
			fl_type_only<T>::
			sort_after_method_overload(
				const_iterator before_first, const_iterator last,
				std::greater<value_type> /*cmp*/
			)
			{
				radix_sort_after(before_first, last, kerbal::type_traits::true_type());
			}

#		if __cplusplus >= 201402L

			template <typename T>
			template <bool is_radix_sort_acceptable_type>
			KERBAL_CONSTEXPR14
			typename kerbal::type_traits::enable_if<is_radix_sort_acceptable_type>::type
			fl_type_only<T>::
			sort_after_method_overload(
				const_iterator before_first, const_iterator last,
				std::less<void> /*cmp*/
			)
			{
				radix_sort_after(before_first, last, kerbal::type_traits::false_type());
			}

			template <typename T>
			template <bool is_radix_sort_acceptable_type>
			KERBAL_CONSTEXPR14
			typename kerbal::type_traits::enable_if<is_radix_sort_acceptable_type>::type
			fl_type_only<T>::
			sort_after_method_overload(
				const_iterator before_first, const_iterator last,
				std::greater<void> /*cmp*/
			)
			{
				radix_sort_after(before_first, last, kerbal::type_traits::true_type());
			}

#		endif

			template <typename T>
			template <bool is_radix_sort_acceptable_type, typename BinaryPredict>
			KERBAL_CONSTEXPR20
			typename kerbal::type_traits::enable_if<!is_radix_sort_acceptable_type>::type
			fl_type_only<T>::
			sort_after_method_overload(
				const_iterator before_first, const_iterator last,
				BinaryPredict cmp
			)
			{
				k_merge_sort_after(before_first, last, cmp);
			}

			template <typename T>
			template <typename BinaryPredict>
			KERBAL_CONSTEXPR14
			void
			fl_type_only<T>::
			k_sort_after(const_iterator before_first, const_iterator last, BinaryPredict cmp)
			{
				sort_after_method_overload<is_forward_list_radix_sort_acceptable_type<value_type>::value>(before_first, last, cmp);
			}

			template <typename T>
			KERBAL_CONSTEXPR14
			void
			fl_type_only<T>::
			k_sort_after(const_iterator before_first, const_iterator last)
			{
				k_sort_after(before_first, last, kerbal::compare::less<value_type>());
			}

			template <typename T>
			template <typename BinaryPredict>
			KERBAL_CONSTEXPR14
			void
			fl_type_only<T>::
			k_sort(BinaryPredict cmp)
			{
				k_sort_after(this->cbefore_begin(), this->cend(), cmp);
			}

			template <typename T>
			KERBAL_CONSTEXPR14
			void
			fl_type_only<T>::
			k_sort()
			{
				k_sort(kerbal::compare::less<value_type>());
			}

			template <typename T>
			template <typename NodeAllocator, typename UnaryPredicate>
			KERBAL_CONSTEXPR20
			typename
			fl_type_only<T>::size_type
			fl_type_only<T>::
			k_remove_after_if_using_allocator(
				NodeAllocator & alloc,
				const_iterator before_first, const_iterator last,
				UnaryPredicate predicate
			)
			{
				size_type cnt = 0;
				const_iterator first(before_first); ++first;
				while (first != last) {
					if (predicate(*first)) {
						++first;
						k_erase_after_using_allocator(alloc, before_first);
						++cnt;
					} else {
						before_first = first;
						++first;
					}
				}
				return cnt;
			}

			template <typename T>
			template <typename NodeAllocator, typename UnaryPredicate>
			KERBAL_CONSTEXPR20
			typename
			fl_type_only<T>::size_type
			fl_type_only<T>::
			k_remove_if_using_allocator(
				NodeAllocator & alloc,
				UnaryPredicate predicate
			)
			{
				return k_remove_after_if_using_allocator(alloc, this->cbefore_begin(), this->cend(), predicate);
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			typename
			fl_type_only<T>::size_type
			fl_type_only<T>::
			k_remove_after_using_allocator(
				NodeAllocator & alloc,
				const_iterator before_first, const_iterator last,
				const_reference val
			)
			{
				return k_remove_after_if_using_allocator(alloc, before_first, last, remove_predict(val));
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			typename
			fl_type_only<T>::size_type
			fl_type_only<T>::
			k_remove_using_allocator(
				NodeAllocator & alloc,
				const_reference val
			)
			{
				return k_remove_after_using_allocator(alloc, this->cbefore_begin(), this->cend(), val);
			}

			template <typename T>
			template <typename NodeAllocator, typename BinaryPredict>
			KERBAL_CONSTEXPR20
			typename
			fl_type_only<T>::size_type
			fl_type_only<T>::
			k_unique_using_allocator(
				NodeAllocator & alloc,
				const_iterator first, const_iterator last,
				BinaryPredict equal_to
			)
			{
				size_type cnt = 0;
				if (first != last) {
					const_iterator forward(first); ++forward;
					while (forward != last) {
						if (equal_to(*first, *forward)) {
							++forward;
							k_destroy_node(alloc, fl_type_unrelated::k_unhook_node_after(first));
							++cnt;
						} else {
							first = forward;
							++forward;
						}
					}
				}
				return cnt;
			}

			template <typename T>
			template <typename NodeAllocator, typename BinaryPredict>
			KERBAL_CONSTEXPR20
			typename
			fl_type_only<T>::size_type
			fl_type_only<T>::
			k_unique_using_allocator(
				NodeAllocator & alloc,
				BinaryPredict equal_to
			)
			{
				return k_unique_using_allocator(alloc, this->cbegin(), this->cend(), equal_to);
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			typename
			fl_type_only<T>::size_type
			fl_type_only<T>::
			k_unique_using_allocator(
				NodeAllocator & alloc,
				const_iterator first, const_iterator last
			)
			{
				return k_unique_using_allocator(alloc, first, last, kerbal::compare::equal_to<value_type>());
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			typename
			fl_type_only<T>::size_type
			fl_type_only<T>::
			k_unique_using_allocator(
				NodeAllocator & alloc
			)
			{
				return this->k_unique_using_allocator(alloc, kerbal::compare::equal_to<value_type>());
			}


		//===================
		// private

#	if __cplusplus >= 201103L

#		if KERBAL_HAS_EXCEPTIONS_SUPPORT

			template <typename T>
			template <bool nothrow_while_construct, typename NodeAllocator, typename ... Args>
			KERBAL_CONSTEXPR20
			typename kerbal::type_traits::enable_if<
				!nothrow_while_construct,
				typename fl_type_only<T>::node *
			>::type
			fl_type_only<T>::
			k_build_new_node_impl(
				NodeAllocator & alloc,
				Args && ... args
			)
			{
				typedef kerbal::memory::allocator_traits<NodeAllocator> node_allocator_traits;
				node * p = node_allocator_traits::allocate_one(alloc);
				try {
					node_allocator_traits::construct(alloc, p, kerbal::utility::in_place_t(), kerbal::utility::forward<Args>(args)...);
				} catch (...) {
					node_allocator_traits::deallocate_one(alloc, p);
					throw;
				}
				return p;
			}

			template <typename T>
			template <bool nothrow_while_construct, typename NodeAllocator, typename ... Args>
			KERBAL_CONSTEXPR20
			typename kerbal::type_traits::enable_if<
				nothrow_while_construct,
				typename fl_type_only<T>::node *
			>::type
			fl_type_only<T>::
			k_build_new_node_impl(
				NodeAllocator & alloc,
				Args && ... args
			)
				KERBAL_CONDITIONAL_NOEXCEPT(
					noexcept(kerbal::memory::allocator_traits<NodeAllocator>::allocate_one(alloc))
				)
			{
				typedef kerbal::memory::allocator_traits<NodeAllocator> node_allocator_traits;
				node * p = node_allocator_traits::allocate_one(alloc);
				node_allocator_traits::construct(alloc, p, kerbal::utility::in_place_t(), kerbal::utility::forward<Args>(args)...);
				return p;
			}

			template <typename T>
			template <typename NodeAllocator, typename ... Args>
			KERBAL_CONSTEXPR20
			typename
			fl_type_only<T>::node *
			fl_type_only<T>::
			k_build_new_node(
				NodeAllocator & alloc,
				Args && ... args
			)
			{
				typedef kerbal::memory::allocator_traits<NodeAllocator> node_allocator_traits;
				typedef
				kerbal::type_traits::bool_constant<
					noexcept(
						node_allocator_traits::construct(
							alloc, kerbal::utility::declval<node *>(),
							kerbal::utility::in_place_t(), kerbal::utility::forward<Args>(args)...
						)
					)
				> nothrow_while_construct;

				return k_build_new_node_impl<nothrow_while_construct::value>(alloc, kerbal::utility::forward<Args>(args)...);
			}

#		else // KERBAL_HAS_EXCEPTIONS_SUPPORT

			template <typename T>
			template <typename NodeAllocator, typename ... Args>
			KERBAL_CONSTEXPR20
			typename
			fl_type_only<T>::node *
			fl_type_only<T>::
			k_build_new_node(
				NodeAllocator & alloc,
				Args && ... args
			)
			{
				typedef kerbal::memory::allocator_traits<NodeAllocator> node_allocator_traits;
				node * p = node_allocator_traits::allocate_one(alloc);
				if (p == NULL) {
					kerbal::utility::throw_this_exception_helper<kerbal::memory::bad_alloc>::throw_this_exception();
				}
				node_allocator_traits::construct(alloc, p, kerbal::utility::in_place_t(), kerbal::utility::forward<Args>(args)...);
				return p;
			}

#		endif // KERBAL_HAS_EXCEPTIONS_SUPPORT

#	else // __cplusplus >= 201103L

#		define EMPTY
#		define LEFT_JOIN_COMMA(exp) , exp
#		define TARGS_DECL(i) typename KERBAL_MACRO_CONCAT(Arg, i)
#		define ARGS_DECL(i) const KERBAL_MACRO_CONCAT(Arg, i) & KERBAL_MACRO_CONCAT(arg, i)
#		define ARGS_USE(i) KERBAL_MACRO_CONCAT(arg, i)

#	if KERBAL_HAS_EXCEPTIONS_SUPPORT

#		define FBODY(i) \
			template <typename T> \
			template < \
				typename NodeAllocator \
				KERBAL_OPT_PPEXPAND_WITH_COMMA_N(LEFT_JOIN_COMMA, EMPTY, TARGS_DECL, i) \
			> \
			typename \
			fl_type_only<T>::node * \
			fl_type_only<T>:: \
			k_build_new_node( \
				NodeAllocator & alloc \
				KERBAL_OPT_PPEXPAND_WITH_COMMA_N(LEFT_JOIN_COMMA, EMPTY, ARGS_DECL, i) \
			) \
			{ \
				typedef kerbal::memory::allocator_traits<NodeAllocator> node_allocator_traits; \
				node * p = node_allocator_traits::allocate_one(alloc); \
				try { \
					node_allocator_traits::construct(alloc, p, kerbal::utility::in_place_t() KERBAL_OPT_PPEXPAND_WITH_COMMA_N(LEFT_JOIN_COMMA, EMPTY, ARGS_USE, i)); \
				} catch (...) { \
					node_allocator_traits::deallocate_one(alloc, p); \
					throw; \
				} \
				return p; \
			} \

#	else // KERBAL_HAS_EXCEPTIONS_SUPPORT

#		define FBODY(i) \
			template <typename T> \
			template <typename NodeAllocator KERBAL_OPT_PPEXPAND_WITH_COMMA_N(LEFT_JOIN_COMMA, EMPTY, TARGS_DECL, i)> \
			typename \
			fl_type_only<T>::node * \
			fl_type_only<T>:: \
			k_build_new_node( \
				NodeAllocator & alloc \
				KERBAL_OPT_PPEXPAND_WITH_COMMA_N(LEFT_JOIN_COMMA, EMPTY, ARGS_DECL, i) \
			) \
			{ \
				typedef kerbal::memory::allocator_traits<NodeAllocator> node_allocator_traits; \
				node * p = node_allocator_traits::allocate_one(alloc); \
				if (p == NULL) { \
					kerbal::utility::throw_this_exception_helper<kerbal::memory::bad_alloc>::throw_this_exception(); \
				} \
				node_allocator_traits::construct(alloc, p, kerbal::utility::in_place_t() KERBAL_OPT_PPEXPAND_WITH_COMMA_N(LEFT_JOIN_COMMA, EMPTY, ARGS_USE, i)); \
				return p; \
			} \

#	endif // KERBAL_HAS_EXCEPTIONS_SUPPORT

			KERBAL_PPEXPAND_N(FBODY, KERBAL_PPEXPAND_EMPTY_SEPARATOR, 0)
			KERBAL_PPEXPAND_N(FBODY, KERBAL_PPEXPAND_EMPTY_SEPARATOR, 20)

#		undef EMPTY
#		undef LEFT_JOIN_COMMA
#		undef TARGS_DECL
#		undef ARGS_DECL
#		undef ARGS_USE
#		undef FBODY

#	endif // __cplusplus >= 201103L


#	if __cplusplus >= 201103L

			template <typename T>
			template <typename NodeAllocator, typename... Args>
			KERBAL_CONSTEXPR20
			sl_node_chain<T>
			fl_type_only<T>::
			k_build_n_new_nodes_unguarded(
				NodeAllocator & alloc,
				size_type n, Args && ... args
			)
			{
				--n;
				node * const start = k_build_new_node(alloc, kerbal::utility::forward<Args>(args)...);
				node * back = start;
#		if KERBAL_HAS_EXCEPTIONS_SUPPORT
				try {
#		endif // KERBAL_HAS_EXCEPTIONS_SUPPORT
					while (n != 0) {
						node * new_node = k_build_new_node(alloc, kerbal::utility::forward<Args>(args)...);
						back->next = new_node;
						back = new_node;
						--n;
					}
					return sl_node_chain<T>(start, back);
#		if KERBAL_HAS_EXCEPTIONS_SUPPORT
				} catch (...) {
					k_consecutive_destroy_node(alloc, start, NULL);
					throw;
				}
#		endif // KERBAL_HAS_EXCEPTIONS_SUPPORT
			}

#	else

#		define EMPTY
#		define LEFT_JOIN_COMMA(exp) , exp
#		define TARGS_DECL(i) typename KERBAL_MACRO_CONCAT(Arg, i)
#		define ARGS_DECL(i) const KERBAL_MACRO_CONCAT(Arg, i) & KERBAL_MACRO_CONCAT(arg, i)
#		define ARGS_USE(i) KERBAL_MACRO_CONCAT(arg, i)

#	if KERBAL_HAS_EXCEPTIONS_SUPPORT

#		define FBODY(i) \
			template <typename T> \
			template <typename NodeAllocator KERBAL_OPT_PPEXPAND_WITH_COMMA_N(LEFT_JOIN_COMMA, EMPTY, TARGS_DECL, i)> \
			sl_node_chain<T> \
			fl_type_only<T>:: \
			k_build_n_new_nodes_unguarded( \
				NodeAllocator & alloc, \
				size_type n \
				KERBAL_OPT_PPEXPAND_WITH_COMMA_N(LEFT_JOIN_COMMA, EMPTY, ARGS_DECL, i) \
			) \
			{ \
				--n; \
				node * const start = k_build_new_node(alloc KERBAL_OPT_PPEXPAND_WITH_COMMA_N(LEFT_JOIN_COMMA, EMPTY, ARGS_USE, i)); \
				node * back = start; \
				try { \
					while (n != 0) { \
						node * new_node = k_build_new_node(alloc KERBAL_OPT_PPEXPAND_WITH_COMMA_N(LEFT_JOIN_COMMA, EMPTY, ARGS_USE, i)); \
						back->next = new_node; \
						back = new_node; \
						--n; \
					} \
					return sl_node_chain<T>(start, back); \
				} catch (...) { \
					k_consecutive_destroy_node(alloc, start, NULL); \
					throw; \
				} \
			} \

#	else // KERBAL_HAS_EXCEPTIONS_SUPPORT

#		define FBODY(i) \
			template <typename T> \
			template <typename NodeAllocator KERBAL_OPT_PPEXPAND_WITH_COMMA_N(LEFT_JOIN_COMMA, EMPTY, TARGS_DECL, i)> \
			sl_node_chain<T> \
			fl_type_only<T>:: \
			k_build_n_new_nodes_unguarded( \
				NodeAllocator & alloc, \
				size_type n \
				KERBAL_OPT_PPEXPAND_WITH_COMMA_N(LEFT_JOIN_COMMA, EMPTY, ARGS_DECL, i) \
			) \
			{ \
				--n; \
				node * const start = k_build_new_node(alloc KERBAL_OPT_PPEXPAND_WITH_COMMA_N(LEFT_JOIN_COMMA, EMPTY, ARGS_USE, i)); \
				node * back = start; \
				while (n != 0) { \
					node * new_node = k_build_new_node(alloc KERBAL_OPT_PPEXPAND_WITH_COMMA_N(LEFT_JOIN_COMMA, EMPTY, ARGS_USE, i)); \
					back->next = new_node; \
					back = new_node; \
					--n; \
				} \
				return sl_node_chain<T>(start, back); \
			} \

#	endif // KERBAL_HAS_EXCEPTIONS_SUPPORT

			KERBAL_PPEXPAND_N(FBODY, KERBAL_PPEXPAND_EMPTY_SEPARATOR, 0)
			KERBAL_PPEXPAND_N(FBODY, KERBAL_PPEXPAND_EMPTY_SEPARATOR, 20)

#		undef EMPTY
#		undef LEFT_JOIN_COMMA
#		undef TARGS_DECL
#		undef ARGS_DECL
#		undef ARGS_USE
#		undef FBODY

#	endif


			template <typename T>
			template <typename NodeAllocator, typename InputIterator>
			KERBAL_CONSTEXPR20
			typename kerbal::type_traits::enable_if<
				kerbal::iterator::is_input_compatible_iterator<InputIterator>::value,
				sl_node_chain<T>
			>::type
			fl_type_only<T>::
			k_build_new_nodes_range_unguarded(
				NodeAllocator & alloc,
				InputIterator first, InputIterator last
			)
			{
				node * const start = k_build_new_node(alloc, *first);
				node * back = start;
#			if KERBAL_HAS_EXCEPTIONS_SUPPORT
				try {
#			endif // KERBAL_HAS_EXCEPTIONS_SUPPORT
					++first;
					while (first != last) {
						node * new_node = k_build_new_node(alloc, *first);
						back->next = new_node;
						back = new_node;
						++first;
					}
					return sl_node_chain<T>(start, back);
#			if KERBAL_HAS_EXCEPTIONS_SUPPORT
				} catch (...) {
					k_consecutive_destroy_node(alloc, start, NULL);
					throw;
				}
#			endif // KERBAL_HAS_EXCEPTIONS_SUPPORT
			}


			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_destroy_node(NodeAllocator & alloc, node_base * p_node_base) KERBAL_NOEXCEPT
			{
				typedef kerbal::memory::allocator_traits<NodeAllocator> node_allocator_traits;
				typedef typename node_allocator_traits::pointer allocator_pointer_type;

				node * p_node = node::reinterpret_as(p_node_base);
				allocator_pointer_type p_node_act = static_cast<allocator_pointer_type>(p_node);
				node_allocator_traits::destroy(alloc, p_node_act);
				node_allocator_traits::deallocate_one(alloc, p_node_act);
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_consecutive_destroy_node_impl(
				NodeAllocator & alloc,
				node_base * first, node_base * last,
				CNSCTV_DES_VER_DEFAULT
			) KERBAL_NOEXCEPT
			{
				while (first != last) {
					node_base * next = first->next;
					k_destroy_node(alloc, first);
					first = next;
				}
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_consecutive_destroy_node_impl(
				NodeAllocator & alloc,
				node_base * first, node_base * last,
				CNSCTV_DES_VER_DESTROY_BUT_NO_DEALLOCATE
			) KERBAL_NOEXCEPT
			{
				typedef kerbal::memory::allocator_traits<NodeAllocator> node_allocator_traits;
				typedef typename node_allocator_traits::pointer allocator_pointer_type;

				while (first != last) {
					node_base * next = first->next;
					node * p_node = node::reinterpret_as(first);
					allocator_pointer_type p_node_act = static_cast<allocator_pointer_type>(p_node);
					node_allocator_traits::destroy(alloc, p_node_act);
					first = next;
				}
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_consecutive_destroy_node_impl(
				NodeAllocator & /*alloc*/,
				node_base * /*first*/, node_base * /*last*/,
				CNSCTV_DES_VER_NO_DESTROY
			) KERBAL_NOEXCEPT
			{
			}

			template <typename T>
			template <typename NodeAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_consecutive_destroy_node(
				NodeAllocator & alloc,
				node_base * first, node_base * last
			) KERBAL_NOEXCEPT
			{
				k_consecutive_destroy_node_impl(alloc, first, last, CNSCTV_DES_VER_DEFAULT());
			}

			template <typename T>
			template <typename U, typename UpstreamAllocator>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_consecutive_destroy_node(
				kerbal::memory::monotonic_allocator<U, UpstreamAllocator> & alloc,
				node_base * first, node_base * last
			) KERBAL_NOEXCEPT
			{
				typedef typename kerbal::type_traits::conditional<
					kerbal::type_traits::try_test_is_trivially_destructible<T>::IS_TRUE::value,
					CNSCTV_DES_VER_NO_DESTROY,
					CNSCTV_DES_VER_DESTROY_BUT_NO_DEALLOCATE
				>::type VER;
				k_consecutive_destroy_node_impl(alloc, first, last, VER());
			}

#		if __cplusplus >= 201703L
#			if __has_include(<memory_resource>)

			template <typename T>
			template <typename Node>
			KERBAL_CONSTEXPR20
			void
			fl_type_only<T>::
			k_consecutive_destroy_node(
				std::pmr::polymorphic_allocator<Node> & alloc,
				node_base * first, node_base * last
			) KERBAL_NOEXCEPT
			{
				typedef kerbal::memory::allocator_traits<std::pmr::polymorphic_allocator<Node> > node_allocator_traits;
				typedef typename node_allocator_traits::value_type real_value_type;

				if (typeid(*alloc.resource()) == typeid(std::pmr::monotonic_buffer_resource)) {
					if constexpr (!kerbal::type_traits::try_test_is_trivially_destructible<real_value_type>::IS_TRUE::value) {
						k_consecutive_destroy_node_impl(alloc, first, last, CNSCTV_DES_VER_DESTROY_BUT_NO_DEALLOCATE());
					}
				} else {
					k_consecutive_destroy_node_impl(alloc, first, last, CNSCTV_DES_VER_DEFAULT());
				}
			}

#			endif
#		endif


		} // namespace detail

	} // namespace container

} // namespace kerbal


#endif // KERBAL_CONTAINER_DETAIL_FORWARD_LIST_BASE_FORWARD_LIST_BASE_IMPL_HPP
